package com.ksyun.registry.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ksyun.registry.domain.dto.HeartBeat;
import com.ksyun.registry.domain.dto.Response;
import com.ksyun.registry.domain.dto.ServiceInstance;
import com.ksyun.registry.service.RegistryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
@RequiredArgsConstructor
public class RegistryServiceImpl implements RegistryService {
    private final Map<String, Set<ServiceInstance>> hashmap=new HashMap<>();
    //存放ID和服务名的对应关系，方便心跳查找
    private final Map<String,String> tmp=new HashMap<>();
    //存放ID和服务时间，通过服务时间来判断是否超时，超时则除掉对应的服务
    private final Map<String,Long> timehashmap=new HashMap<>();
    //索引库，使用ServiceName和Integer来进行操作
    private final Map<String,Integer> indexhashmap=new HashMap<>();

    @Override
    public Response register(ServiceInstance serviceInstance) {
        //查询是否已经存在该实例
        if (hashmap.containsKey(serviceInstance.getServiceName())){
            //已存在该实例服务名称，判断内部示例是否一致
            Set<ServiceInstance> serviceInstances = hashmap.get(serviceInstance.getServiceName());
            if (serviceInstances.contains(serviceInstance)){
                return new Response(400,"Already Have!");
            }else {
                serviceInstances.add(serviceInstance);
                hashmap.put(serviceInstance.getServiceName(),serviceInstances);
                tmp.put(serviceInstance.getServiceId(),serviceInstance.getServiceName());
                //记录服务的时间
                timehashmap.put(serviceInstance.getServiceId(),System.currentTimeMillis());
                //发送唤醒通知
                try {
                    registerPost(serviceInstance);
                }catch (Exception e){

                }
                return new Response(200,"success");
            }
        }else {
            //不存在
            Set<ServiceInstance> serviceInstances=new HashSet<>();
            serviceInstances.add(serviceInstance);
            hashmap.put(serviceInstance.getServiceName(),serviceInstances);
            tmp.put(serviceInstance.getServiceId(),serviceInstance.getServiceName());
            //记录服务的时间
            timehashmap.put(serviceInstance.getServiceId(),System.currentTimeMillis());
            indexhashmap.put(serviceInstance.getServiceName(),0);
            //发送唤醒通知
            try {
                registerPost(serviceInstance);
            }catch (Exception e){

            }
            return new Response(200,"success");
        }
    }
    public void registerPost(ServiceInstance serviceInstance) throws Exception {
        // 执行通知，通知已经完成注册，可以开始发送请求
        String ipAddress = serviceInstance.getIpAddress();
        int port = serviceInstance.getPort();
        // 尝试调用远程的 awake 接口，完成唤醒操作
        String url = "http://" + ipAddress + ":" + port + "/api/awake";
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(serviceInstance);
        HttpPost httpPost = new HttpPost(url);
        StringEntity entity = new StringEntity(json);
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json");
        // 设置超时
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(200) // 连接超时设置为0.2秒
                .setSocketTimeout(200)  // 读取超时设置为0.2秒
                .build();
        CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .build();

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            // 处理响应,不需要处理
        } catch (Exception e) {
        } finally {
            httpClient.close(); // 确保客户端被关闭
        }
    }
    @Override
    public Response unregister(ServiceInstance serviceInstance) {
        if (hashmap.containsKey(serviceInstance.getServiceName())){
            //存在服务
            Set<ServiceInstance> serviceInstances = hashmap.get(serviceInstance.getServiceName());
            if (serviceInstances.contains(serviceInstance)){
                //存在,移除对应表当中的数值
                tmp.remove(serviceInstance.getServiceId(),serviceInstance.getServiceName());
                hashmap.remove(serviceInstance.getServiceId());
                serviceInstances.remove(serviceInstance);
                hashmap.put(serviceInstance.getServiceName(),serviceInstances);
                //发送睡眠消息
                try {
                    unregisterPost(serviceInstance);
                }catch (Exception e){

                }
                return new Response(200,"注销成功！");
            }else {
                //注销失败，不存在
                return new Response(400,"不存在该服务");
            }
        }else {
            //不存在该服务
            return new Response(400,"不存在该服务");
        }
    }
    public void unregisterPost(ServiceInstance serviceInstance) throws Exception {
        // 执行通知，通知已经完成注册，可以开始发送请求
        String ipAddress = serviceInstance.getIpAddress();
        int port = serviceInstance.getPort();
        // 尝试调用远程的 awake 接口，完成睡眠操作
        String url = "http://" + ipAddress + ":" + port + "/api/sleep";
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(serviceInstance);

        HttpPost httpPost = new HttpPost(url);
        StringEntity entity = new StringEntity(json);
        httpPost.setEntity(entity);
        //设置请求头类型
        httpPost.setHeader("Content-Type", "application/json");
        // 设置超时
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(200) // 连接超时设置为0.2秒
                .setSocketTimeout(200)  // 读取超时设置为0.2秒
                .build();
        CloseableHttpClient httpClient = HttpClients.custom()
                .setDefaultRequestConfig(requestConfig)
                .build();

        try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
            // 处理响应,不需要处理
        } catch (Exception e) {
        } finally {
            httpClient.close(); // 确保客户端被关闭
        }
    }
    @Override
    public List<ServiceInstance> discovery(String name) {
        //判断名字是否为空
        if (name==null){
            //名字为空，返回所有列表
            List<ServiceInstance> serviceInstances=new ArrayList<>();
            hashmap.forEach((o1,o2)->{
                o2.forEach(o3->{
                    serviceInstances.add(o3);
                });
            });
            return serviceInstances;
        }else {
            //名字非空
            if (hashmap.containsKey(name)){
                //返回负载均衡算法选择的一个实例
                Set<ServiceInstance> serviceInstances1 = hashmap.get(name);
                Integer index = indexhashmap.get(name)%serviceInstances1.size();
                List<ServiceInstance> serviceInstances=new ArrayList<>(serviceInstances1);
                ServiceInstance serviceInstance = serviceInstances.get(index);
                indexhashmap.put(name,++index);
                List<ServiceInstance> res=new ArrayList<>();
                res.add(serviceInstance);
                return res;
            }else {
                return Collections.emptyList();
            }
        }
    }

    @Override
    public Response heartbeat(HeartBeat heartBeat) {
        //检查是否存在该实例
        String serviceId = heartBeat.getServiceId();
        //判断是否存在
        if (tmp.containsKey(serviceId)){
            // 存在，取出对应的服务实例，向其发送心跳
            String ipAddress = heartBeat.getIpAddress();
            int port = heartBeat.getPort();
            String url = "http://" + ipAddress + ":" + port + "/api/heartbeat"; // 假设心跳服务的 URL
            //发送心跳信息

            //取出服务实例,调整时间
            timehashmap.put(serviceId,System.currentTimeMillis());
            return new Response(200,"成功发送心跳");
        }else {
            //不存在
            return new Response(400,"该服务实例未注册!");
        }
    }
    // 每1秒执行一次
    @Scheduled(fixedRate = 1000)
    public void executeTest() {
        //遍历时间哈希表，然后根据时间哈希表来确定删除的对象
        if (timehashmap.isEmpty()){
            return;
        }
        timehashmap.forEach((o1,o2)->{
            //获取到现在的时间和存储的o2时间比较，比较两者的差值，超过60s，则执行删除
            long l = System.currentTimeMillis() - o2;
            if (l>=60000){
                //执行删除
                delete(o1);
                //删除成功
            }
        });
    }
    public void delete(String serviceId){
        //根据服务ID删除
        //获取服务名称
        String serviceName = tmp.get(serviceId);
        Set<ServiceInstance> serviceInstances = hashmap.get(serviceName);
        serviceInstances.forEach(o1->{
            if (o1.getServiceId().equals(serviceId)){
                //id相等，进行删除操作，删除之后再放回原哈希表
                serviceInstances.remove(o1);
                hashmap.put(serviceName,serviceInstances);
                return;
            }
        });
    }
}
